package site.sorghum.ddl.config;

import cn.hutool.core.util.ClassUtil;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.noear.wood.annotation.Table;
import site.sorghum.ddl.base.BaseDdlWrapper;
import site.sorghum.ddl.base.JavaCoreEntityGenerate;
import site.sorghum.ddl.compare.TableCompare;
import site.sorghum.ddl.entity.DdlTableWrap;
import site.sorghum.ddl.exception.DdlException;

import java.util.HashMap;
import java.util.List;
import java.util.Set;

/**
 * 初始化类 尽量支持各类IOC框架
 */
@Data
@Slf4j
public abstract class InitConfig {
    /**
     * java类 -> 数据定义
     **/
    public final HashMap<Class<?>, DdlTableWrap> javaMap = new HashMap<>();

    /**
     * [JAVA]数据库表 -> 数据定义
     **/
    public final HashMap<String, DdlTableWrap> javaTableMap = new HashMap<>();

    /**
     * [数据库]数据库表 -> 数据定义
     **/
    public final HashMap<String, DdlTableWrap> dbTableMap = new HashMap<>();

    BaseDdlWrapper ddlWrapper;

    JavaCoreEntityGenerate coreEntityGenerate;

    public InitConfig(
            BaseDdlWrapper ddlWrapper,
            JavaCoreEntityGenerate coreEntityGenerate
    ) {
        this.ddlWrapper = ddlWrapper;
        this.coreEntityGenerate = coreEntityGenerate;
        init();
    }

    @SneakyThrows
    public void init() {
        DdlGlobalConfig.basePackages.parallelStream().forEach(basePackage -> {
            Set<Class<?>> classes = null;
            try {
                // classes = ClassUtil.scanPackage(basePackage);
                classes = ClassUtil.scanPackageByAnnotation(basePackage, Table.class);
                classes.parallelStream()
                        .filter(aClass -> !aClass.isAnonymousClass())
                        .filter(aClass -> !aClass.isInterface())
                        .filter(aClass -> !aClass.getName().contains("$"))
                        .filter(aClass -> aClass.getDeclaredAnnotation(site.sorghum.ddl.annotation.DdlExclude.class) == null)
                        // 过滤flex自动生成的
                        .filter(aClass -> !aClass.getSuperclass().getName().equals("com.mybatisflex.core.table.TableDef"))
                        .forEach(aClass -> {
                            DdlTableWrap wrap = coreEntityGenerate.get(aClass);
                            synchronized (this) {
                                javaMap.put(aClass, wrap);
                                javaTableMap.put(wrap.getName(), wrap);
                            }
                        });
            } catch (Exception e) {
                throw new DdlException(e);
            }
        });

        // 优化数据库元数据加载
        ddlWrapper.fetchAllTables().parallelStream()
                .map(ddlWrapper::fromDataSource)
                .forEach(wrap -> dbTableMap.put(wrap.getName(), wrap));

        runCreateTask();

        runAddColumnTask();

        runAddIndexTask();

        runDropIndexTask();

        runDropColumnTask();
    }

    public void runCreateTask() {
        if (!DdlGlobalConfig.createTable) {
            log.info("[Sorghum-DDL] 自动建表服务已暂停,可手动调用InitConfig::runCreateTask.");
            return;
        } else {
            log.info("[Sorghum-DDL] 自动建表服务已开启.");
        }
        javaTableMap.keySet().stream()
                .filter(tableName -> !dbTableMap.containsKey(tableName))
                .forEach(tableName -> {
                    log.info("[Sorghum-DDL] 自动建表: {}", tableName);
                    DdlTableWrap wrap = javaTableMap.get(tableName);
                    List<String> sql = ddlWrapper.dialect().generateCreateTableDDL(wrap);
                    sql.forEach(ddlWrapper::exec);
                });
    }

    public void runAddColumnTask() {
        if (!DdlGlobalConfig.addColumn) {
            log.info("[Sorghum-DDL] 自动添加列服务已暂停,可手动调用InitConfig::runAddColumnTask.");
            return;
        } else {
            log.info("[Sorghum-DDL] 自动添加列服务已开启.");
        }
        javaTableMap.keySet().stream()
                .filter(dbTableMap::containsKey)
                .forEach(tableName -> {
                    DdlTableWrap javaTable = javaTableMap.get(tableName);
                    DdlTableWrap dbTable = dbTableMap.get(tableName);
                    List<String> sqlList = TableCompare.compareAddColumn(ddlWrapper.dialect(), javaTable, dbTable);
                    if (sqlList.isEmpty()) {
                        return;
                    }
                    log.info("[Sorghum-DDL] 自动添加列: {}", tableName);
                    sqlList.forEach(ddlWrapper::exec);
                });
    }

    public void runAddIndexTask() {
        if (!DdlGlobalConfig.addIndex) {
            log.info("[Sorghum-DDL] 自动添加索引服务已暂停,可手动调用InitConfig::runAddIndexTask.");
            return;
        } else {
            log.info("[Sorghum-DDL] 自动添加索引服务已开启.");
        }
        javaTableMap.keySet().stream()
                .filter(dbTableMap::containsKey)
                .forEach(tableName -> {
                    DdlTableWrap javaTable = javaTableMap.get(tableName);
                    DdlTableWrap dbTable = dbTableMap.get(tableName);
                    List<String> sqlList = TableCompare.compareAddIndex(ddlWrapper.dialect(), javaTable, dbTable);
                    if (sqlList.isEmpty()) {
                        return;
                    }
                    log.info("[Sorghum-DDL] 自动添加索引: {}", tableName);
                    sqlList.forEach(ddlWrapper::exec);
                });

    }

    public void runDropColumnTask() {
        if (!DdlGlobalConfig.dropColumn) {
            log.info("[Sorghum-DDL] 自动删除列服务已暂停,可手动调用InitConfig::runDropColumnTask.");
            return;
        } else {
            log.info("[Sorghum-DDL] 自动删除列服务已开启.");
        }
        javaTableMap.keySet().stream()
                .filter(dbTableMap::containsKey)
                .forEach(tableName -> {
                    DdlTableWrap javaTable = javaTableMap.get(tableName);
                    DdlTableWrap dbTable = dbTableMap.get(tableName);
                    List<String> sqlList = TableCompare.compareDropColumn(ddlWrapper.dialect(), javaTable, dbTable);
                    if (sqlList.isEmpty()) {
                        return;
                    }
                    log.info("[Sorghum-DDL] 自动删除列: {}", tableName);
                    sqlList.forEach(ddlWrapper::exec);
                });

    }

    public void runDropIndexTask() {
        if (!DdlGlobalConfig.dropIndex) {
            log.info("[Sorghum-DDL] 自动删除索引服务已暂停,可手动调用InitConfig::runDropIndexTask.");
            return;
        } else {
            log.info("[Sorghum-DDL] 自动删除索引服务已开启.");
        }
        javaTableMap.keySet().stream()
                .filter(dbTableMap::containsKey)
                .forEach(tableName -> {
                    DdlTableWrap javaTable = javaTableMap.get(tableName);
                    DdlTableWrap dbTable = dbTableMap.get(tableName);
                    List<String> sqlList = TableCompare.compareDropIndex(ddlWrapper.dialect(), javaTable, dbTable);
                    if (sqlList.isEmpty()) {
                        return;
                    }
                    log.info("[Sorghum-DDL] 自动删除索引: {}", tableName);
                    sqlList.forEach(ddlWrapper::exec);
                });
    }
}
